<template>
  <div>
    <el-card class="box-card">
      <el-breadcrumb separator-class="el-icon-arrow-right">
        <el-breadcrumb-item :to="{ path: '/welcome' }">首页</el-breadcrumb-item>
        <el-breadcrumb-item>权限管理</el-breadcrumb-item>
        <el-breadcrumb-item>角色列表</el-breadcrumb-item>
      </el-breadcrumb>

      <el-row :gutter="20">
        <el-col>
          <el-button type="primary" @click="shoAddRoleDialogVisible">添加角色</el-button>
        </el-col>
      </el-row>
      <el-table
        v-loading="loading"
        element-loading-text="拼命加载中"
        element-loading-spinner="el-icon-loading"
        element-loading-background="rgba(255, 255, 255, 0.7)"
        :data="roles" border stripe style="width: 100%">
        <!-- 展开列 -->
        <el-table-column type="expand">
          <template v-slot="scope">
            <!--  渲染一级权限 -->
            <el-row :class="['alignCenter', 'bdBottom', i1 === 0 ? 'bdTop' : '']" :gutter="20"
                    v-for="(item1, i1) in scope.row.children" :key="item1.authName">
              <el-col :span="5">
                <el-tag closable @close="removeRightById(scope.row, item1.id)">
                  {{ item1.authName }}
                </el-tag>
                <i class="el-icon-caret-right"></i>
              </el-col>
              <!--  渲染二级权限 -->
              <el-col :span="19">
                <el-row :class="['alignCenter', i2 !== 0 ? 'bdTop' : '']" :gutter="20"
                        v-for="(item2, i2) in item1.children" :key="i2">
                  <el-col :span="5">
                    <el-tag type="success" closable @close="removeRightById(scope.row, item2.id)">
                      {{ item2.authName }}
                    </el-tag>
                    <i class="el-icon-caret-right"></i>
                  </el-col>
                  <el-col :span="19">
                    <el-tag closable type="warning" v-for="(item3, i3) in item2.children" :key="i3"
                            @close="removeRightById(scope.row, item3.id)">
                      {{ item3.authName }}
                    </el-tag>
                  </el-col>
                </el-row>
              </el-col>
            </el-row>
          </template>
        </el-table-column>
        <!-- 索引列 -->
        <el-table-column type="index" label="#">
        </el-table-column>
        <el-table-column prop="roleName" label="角色名称">
        </el-table-column>
        <el-table-column prop="roleDesc" label="角色描述">
        </el-table-column>
        <el-table-column label="操作">
          <template v-slot="scope">
            <el-button size="mini" type="primary" icon="el-icon-edit">编辑</el-button>
            <el-button size="mini" type="danger" icon="el-icon-delete"
                       @click="deleteRole(scope.row.id,scope.$index)">删除
            </el-button>
            <el-button size="mini" type="warning" icon="el-icon-setting"
                       @click="showSetRightsDialog(scope.row)">分配权限
            </el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-card>
    <!-- 分配角色对话框 -->
    <el-dialog @close="checkedRights = []" title="分配权限" :visible.sync="setRightsDialogVisible" width="50%">
      <el-tree show-checkbox :data="treeRights" :props="rightsProps" node-key="id" :default-checked-keys="checkedRights"
               default-expand-all ref="treeRightsRef"></el-tree>
      <span slot="footer" class="dialog-footer">
        <el-button @click="closeSetRightsDialogVisible()">取 消</el-button>
        <el-button type="primary" @click="editRights">确 定</el-button>
      </span>
    </el-dialog>
    <!-- 添加角色对话框 -->
    <el-dialog
      title="添加角色"
      @close="closeAddRoleDialog"
      :visible.sync="addRoleDialogVisible">
      <el-form ref="addRoleFormRef" :rules="addRoleRules" :model="addRoleForm" label-width="80px">
        <el-form-item prop="roleName" label="角色名称">
          <el-input v-model="addRoleForm.roleName"></el-input>
        </el-form-item>
        <el-form-item prop="roleDesc" label="角色描述">
          <el-input type="textarea" rows="5" v-model="addRoleForm.roleDesc"></el-input>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="addRoleDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="addRole()" :loading="addRoleProhibit">确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
import common from '@/assets/js/common'

export default {
  data () {
    return {
      loading: false,
      addRoleProhibit: false,
      // 角色列表
      roles: [],
      // 设置角色权限对话框是否显示
      setRightsDialogVisible: false,
      // 所有权限树形控件
      treeRights: [],
      // 树形空间属性，节点文本字段名、子节点字段名
      rightsProps: {
        children: 'children',
        label: 'authName'
      },
      // 默认选中的 node-key 列表
      checkedRights: [],
      // 当前选中角色
      currentRole: {},
      // 新增角色对话框
      addRoleDialogVisible: false,
      // 新增角色表单
      addRoleForm: {},
      addRoleRules: {
        roleName: this.config.rules.roleNameRules,
        roleDesc: this.config.rules.roleDescRules
      }
    }
  },
  created () {
    // 刷新角色列表
    this.getRoles()
  },
  methods: {
    // 获取角色列表
    async getRoles (notRender) {
      this.loading = true
      const { data: res } = await this.http.get('roles')
      if (!notRender) {
        this.roles = res.data
      }
      this.loading = false
      return res.data
    },
    // 删除角色权限 当前角色，权限id
    async removeRightById (role, rightId) {
      const confirmResult = await this.$confirm('此操作将删除角色权限, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).catch(error => error)
      if (confirmResult === 'cancel') return
      const { data: res } = await this.http.delete(`roles/${role.id}/rights/${rightId}`)
      if (res.meta.status !== 200) return this.$message.error(`${res.meta.status} ${res.meta.msg}`)
      role.children = res.data
      this.$message.success(`${res.meta.status} ${res.meta.msg}`)
    },
    // 显示分配权限对话框
    async showSetRightsDialog (role) {
      const { data: res } = await this.http.get('rights/tree')
      this.treeRights = res.data

      role.children.forEach(item => this.getCheckedNodeKeysRecursion(item, this.checkedRights))
      this.currentRole = role
      this.setRightsDialogVisible = true
    },
    // 关闭分配权限对话框
    closeSetRightsDialogVisible () {
      this.setRightsDialogVisible = false
      this.currentRole = null
    },
    // 递归获取已选中叶子结点 node-key
    getCheckedNodeKeysRecursion (node, arr) {
      if (node.children) {
        return node.children.forEach(item => this.getCheckedNodeKeysRecursion(item, arr))
      }
      arr.push(node.id)
    },
    // 分配权限
    async editRights () {
      // 更新权限信息
      const currentRoleId = this.currentRole.id
      const keys = [...this.$refs.treeRightsRef.getCheckedKeys(), ...this.$refs.treeRightsRef.getHalfCheckedKeys()]
      const { data: res } = await this.http.post(`roles/${currentRoleId}/rights`, { rids: keys.join(',') })
      if (this.failed(res, 200, true)) return
      // 关闭赋权对话框
      this.closeSetRightsDialogVisible()

      // 获取新的角色信息，不进行表格渲染
      const newRoles = await this.getRoles(true)
      // 找到当前修改的角色在修改后的角色列表中的信息，以及当前角色已渲染的数据索引
      // 将修改后的角色权限信息赋值到缓存数据中，以实现局部渲染。
      const newCurrentRole = newRoles.find(r => r.id === currentRoleId)
      const currentRoleIndex = this.roles.findIndex(r => r.id === currentRoleId)
      this.roles[currentRoleIndex].children = newCurrentRole.children
    },
    shoAddRoleDialogVisible () {
      this.addRoleDialogVisible = true
    },
    addRole () {
      this.$refs.addRoleFormRef.validate(async valid => {
        await common.preventDuplicateSubmit(prohibit => {
          this.addRoleProhibit = prohibit
        }, async () => {
          if (!valid) return this.$message.error('请正确填写表单')
          const { data: res } = await this.http.post('roles', this.addRoleForm)
          if (res.meta.status !== 201) return this.$message.error(`${res.meta.status} ${res.meta.msg}`)
          this.$message.success(`${res.meta.status} ${res.meta.msg}`)
          this.addRoleDialogVisible = false
          await this.getRoles()
        })
      })
    },
    // 删除角色
    async deleteRole (id, index) {
      const confirmResult = await this.$confirm('此操作将永久删除该角色, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).catch(err => err)
      if (confirmResult === 'cancel') return
      const { data: res } = await this.http.delete(`roles/${id}`)
      if (res.meta.status !== 200) return this.$message.error(`${res.meta.status} ${res.meta.msg}`)
      this.$message.success(`${res.meta.status} ${res.meta.msg}`)
      this.roles.splice(index, 1)
    },
    closeAddRoleDialog () {
      this.addRoleForm = {}
    }
  }
}
</script>

<style lang="less" scoped>
.el-tag {
  margin: 7px;
}

.bdTop {
  border-top: 1px solid #efefef;
}

.bdBottom {
  border-bottom: 1px solid #efefef;
}

.alignCenter {
  display: flex;
  align-items: center;
}
</style>
